// Author: Bjorn Schobben


#include "Texture.h"
#include <FreeImagePlus.h>

// Create empty texture
Texture::Texture(int newHeight, int newWidth): height(newHeight), width(newWidth)
{
	Allocate();
}


// Create texture from image file
Texture::Texture(const std::string& filename): pixeldata(0), solidColor(255, 255, 255)
{
	fipImage image;
	RGBQUAD color;


	// Load image from filename
	if (FALSE == image.load(filename.c_str()))
	{
		throw std::runtime_error("Error loading texture "+filename);
	}

	width = image.getWidth();
	height = image.getHeight();

	Allocate();

	// Convert each rgbquad into a pixel, and pick a usercolor

	Pixel mostCommonColor(0,0,0);
	unsigned int mostCommonColorCount = 0, otherColorCount = 0;

	for(unsigned int y = 0; y < height; y++)
	{
		for(unsigned int x = 0; x < width; x++)
		{
			if (!image.getPixelColor(x, height-y-1, &color))
			{
				throw std::runtime_error("Error loading texture");
			}

			Pixel pixel = Pixel(color.rgbRed, color.rgbGreen, color.rgbBlue);

			SetPixel( x, y, pixel );

			// Try to generate a usercolor which fits for this texture
			if (pixel != mostCommonColor)
			{
				otherColorCount++;

				if (otherColorCount > mostCommonColorCount*5)
				{
					otherColorCount = 0;
					mostCommonColorCount = 0;
					mostCommonColor = pixel;
				}
			}
			else
			{
				mostCommonColorCount++;
			}
		}
	}

	SetUserColor(mostCommonColor);
}

// Create texture from solid color
Texture::Texture(const Pixel& solid): pixeldata(0), height(DEFAULT_SOLIDHEIGHT), width(DEFAULT_SOLIDWIDTH), solidColor(solid), userColor(solid)
{
	
}

// Copy texture
Texture::Texture(const Texture& rhs): width(rhs.width), height(rhs.height), pixeldata(0), solidColor(rhs.solidColor), userColor(rhs.userColor)
{
	if (rhs.pixeldata)
	{
		Allocate();

		for(unsigned int y = 0; y < height; y++)
		{
			for(unsigned int x = 0; x < width; x++)
			{
				pixeldata[y*width+x] = rhs.GetPixel(x, y);
			}
		}
	}
}

Texture::~Texture()
{
	Clear();
}

void Texture::Clear()
{
	if (pixeldata)
	{
		delete[] pixeldata;
		pixeldata = 0;
	}
}

Texture& Texture::operator=(const Texture& rhs)
{
	Clear();

	width = rhs.width;
	height = rhs.height;
	solidColor = rhs.solidColor;
	userColor = rhs.userColor;

	if (rhs.pixeldata)
	{
		Allocate();

		for(unsigned int y = 0; y < height; y++)
		{
			for(unsigned int x = 0; x < width; x++)
			{
				pixeldata[y*width+x] = rhs.GetPixel(x, y);
			}
		}
	}

	return *this;
}

const Pixel& Texture::GetUserColor() const
{
	return userColor;
}

void Texture::SetUserColor(const Pixel& color)
{
	userColor = color;
}

const std::string& Texture::GetName() const
{
	return name;
}

void Texture::SetName(const std::string& newName)
{
	name = newName;
}

// Allocate pixels for this texture
void Texture::Allocate()
{
	pixeldata = new Pixel[height * width];
}

unsigned int Texture::GetHeight() const
{
	return height;
}

unsigned int Texture::GetWidth() const
{
	return width;
}

void Texture::SetPixel(unsigned int x, unsigned int y, const Pixel& color)
{
	if (pixeldata)
	{
		pixeldata[y*width+x] = color;
	}
}

const Pixel& Texture::GetPixel(unsigned int x, unsigned int y) const
{
	if (pixeldata)
	{
		return pixeldata[y*width+x];
	}
	else
	{
		return solidColor;
	}
}

bool Texture::IsSolidColor() const
{
	return pixeldata == 0;
}

const Pixel& Texture::GetSolidColor() const
{
	return solidColor;
}

void Texture::SetSolidColor(const Pixel& solid)
{
	solidColor = solid;
}

const Pixel& Texture::operator()(unsigned int x, unsigned int y) const
{
	return GetPixel(x, y);
}